package com.chenyun.common.utils;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.chenyun.common.exceptions.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.io.Serializable;
import java.lang.reflect.Method;

/**
 * SpelUtil：
 * Description:
 *
 * @author: Lonni
 * @date: 2024/1/19 0019 17:09
 */
public class SpelUtil implements Serializable {

    private SpelUtil() {
    }

    public static SpelUtil me = new SpelUtil();

    private final Logger log = LoggerFactory.getLogger(SpelUtil.class);
    /**
     * 定义spel表达式解析器
     */
    private final ExpressionParser parser = new SpelExpressionParser();
    /**
     * 定义spel解析模版
     */
    private final ParserContext parserContext = new TemplateParserContext();
    /**
     * 定义spel上下文对象进行解析
     */
    private final EvaluationContext context = new StandardEvaluationContext();
    /**
     * 方法参数解析器
     */
    private final ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();


    /**
     * 解析spel表达式
     *
     * @param spelValue
     * @param point
     */
    public String converSpEl(String spelValue, JoinPoint point) {
        String conSpELStr = "";
        if (!StrUtil.containsAny(spelValue, "#")) {
            log.debug("没有spel表达式,不解析");
            return conSpELStr;
        }
        Object[] args = point.getArgs();
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Class<?> targetClass = method.getDeclaringClass();
        //获取方法上的 参数名称
        String[] parameterNames = pnd.getParameterNames(method);
        if (ArrayUtil.isEmpty(parameterNames)) {
            throw new BusinessException("解析SpEL表达式异常,没有参数!");
        }
        //赋值
        for (int i = 0; i < parameterNames.length; i++) {
            context.setVariable(parameterNames[i], args[i]);
        }
        try {
            Expression expression;
            //判断开头是否已 #{ 和 结尾 }
            if (StringUtils.startsWith(spelValue, parserContext.getExpressionPrefix())
                    && StringUtils.endsWith(spelValue, parserContext.getExpressionSuffix())) {
                expression = parser.parseExpression(spelValue, parserContext);
            } else {
                expression = parser.parseExpression(spelValue);
            }
            conSpELStr = expression.getValue(context, String.class);
            return conSpELStr;
        } catch (Exception e) {
            log.error("解析表达式错误", e);
            throw new BusinessException("解析表达式错误:" + e.getMessage());
        }

    }


}



